package Log

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"log"
	"os"
	"sync"
)

type asyncFileWriter struct {
	file     *os.File
	logCh    chan []byte
	wg       sync.WaitGroup
	fileName string
}

func newAsyncFileWriter(fileName string) *asyncFileWriter {
	file, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatal(err)
	}

	return &asyncFileWriter{
		file:     file,
		logCh:    make(chan []byte, 1000),
		wg:       sync.WaitGroup{},
		fileName: fileName,
	}
}

func (w *asyncFileWriter) startWriter() {
	w.wg.Add(1)
	go func() {
		defer w.wg.Done()
		for logData := range w.logCh {
			_, err := w.file.Write(logData)
			if err != nil {
				log.Println("Error writing log to file:", err)
			}
		}
	}()
}

func (w *asyncFileWriter) Write(p []byte) (n int, err error) {
	w.logCh <- p
	return len(p), nil
}

func (w *asyncFileWriter) Sync() error {
	close(w.logCh)
	w.wg.Wait()
	return w.file.Close()
}

func (w *asyncFileWriter) Close() error {
	return w.Sync()
}

func InitLoggerWithFile() *zap.Logger {
	logger, err := zap.NewProduction()
	if err != nil {
		log.Fatal(err)
	}

	asyncWriter := newAsyncFileWriter("application.log")
	asyncWriter.startWriter()

	logger = logger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
		return zapcore.NewCore(zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), asyncWriter, zap.InfoLevel)
	}))

	return logger
}
